package com.jt.service.impl;

import com.jt.service.FileService;
import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Service
@PropertySource("classpath:/image.properties")//动态导入pro配置文件
public class FileServiceImpl implements FileService {

    //最优做法：使用配置文件动态为属性赋值
    //private String localDirPath = "D:/images";
    //private String preURLPath = "http://image.jt.com";
    @Value("${file.localDirPath}")
    private String localDirPath;
    @Value("${file.preURLPath}")
    private String preURLPath;

    /**
     * 1.验证上传的文件是图片!  jpg|png|gif  采用正则的方式校验
     * 2.防止恶意程序攻击      验证图片是否有宽度和高度.
     * 3.文件分目录存储
     * 例如: /2021/11/11/
     * 例如2: hash码 8位hash xx/xx/xx/xx
     * 数据hash时 特征:因为是算法 可能造成数据分配不均!!!
     * 4.防止文件重名,修改文件名称 UUID
     *
     * @param file
     * @return
     */

    @Override
    public ImageVO upload(MultipartFile file) {
        //1. 校验图片类型  正则表达式  a.jpg
        //1.1 获取文件名称
        String filename = file.getOriginalFilename();
        //1.3 将名称全部小写 避免正则校验出现bug
        filename.toLowerCase();
        //1.2 正则校验
        // ^ 开始 . 任意字符 + 字符出现一次或多次 （* 出现零次或任意次） \\. 转义的点 (xx|xx) 选择 $ 结束
        if (!filename.matches("^.+\\.(jpg|png|gif)$")) {
            return null;//不匹配则返回null，终止程序
        }

        try {
            //2. 校验文件是否为恶意程序
            //2.1 将文件转化为图片对象 运用 图像API 获取宽高
            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
            int height = bufferedImage.getHeight();
            int width = bufferedImage.getWidth();
            if (height == 0 || width == 0) {
                return null;//不匹配 终止程序
            }

            //3. 实现分目录存储
            //3.1 按照事件分配目录 /yyyy/MM/dd
            String dateDirPath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
            //3.2 拼接目录"D:/images/yyyy/MM/dd"
            String localDir = localDirPath + dateDirPath;
            //创建目录
            File dirFile = new File(localDir);
            if (!dirFile.exists()) {//如果目录不存在，则创建目录
                dirFile.mkdirs();
            }

            //4. 修改文件名
            String uuid = UUID.randomUUID().toString()
                    .replace("-", "");
            //获取后缀  .jpg
            int index = filename.lastIndexOf(".");
            String fileType = filename.substring(index);
            //uuid.jpg
            String realFileName = uuid + fileType;

            //5. 实现文件上传
            //5.1 拼接文件全路径  目录/文件名
            String localFilePath = localDir + realFileName;//D:/images/2021/07/13/c5c149bcae064d1db3dc9d1ff396ccf5.jpg
            //5.2 完成文件上传操作
            file.transferTo(new File(localFilePath));

            //封装ImageVO
            //真实磁盘地址 D:/images/2021/07/13/c5c149bcae064d1db3dc9d1ff396ccf5.jpg
            //虚拟动态地址 virtualPath  不带磁盘的本地存储路径 虚拟动态目录  /2021/07/13/c5c149bcae064d1db3dc9d1ff396ccf5.jpg
            String virtualPath = dateDirPath + realFileName;
            //图片访问的网络地址：urlPath "http://image.jt.com/2021/07/13/c5c149bcae064d1db3dc9d1ff396ccf5.jpg"
            String urlPath = preURLPath + virtualPath;
            return new ImageVO(virtualPath, urlPath, realFileName);

        } catch (IOException e) {
            e.printStackTrace();
            return null;//出现IO异常，返回null，终止程序
        }
    }

    //删除文件 1. 准备文件全路径   2. 执行删除操作
    @Override
    public void deleteFile(String virtualPath) {
        //D:/images/yyyy/MM/dd/uuid.jpg
        String path = localDirPath + virtualPath;
        //通过文件对象删除
        File file = new File(path);
        file.delete();
    }

    /**
     * 步骤:
     *     1.准备文件上传的目录
     *     2.获取文件上传名称
     *     3.拼接文件路径
     *     4.实现文件上传
     *
     *  关于业务层异常处理原则:
     *      将检查异常转化为运行时异常,交给全局异常处理机制
     *
     * @param file
     */
//    @Override
//    public void upload(MultipartFile file) {
//        String filePath = "D:/images/";//定义文件路径
//        File fileDir = new File(filePath);//创建文件
//        //判断目录是否存在
//        if (!fileDir.exists()){
//            fileDir.mkdirs();//创建多级目录
//        }
//        //获取文件名
//        String filename = file.getOriginalFilename();
//        //文件上传目录路径
//        String path = filePath + filename;
//        //实现文件上传
//        try {
//            file.transferTo(new File(path));
//        } catch (IOException e) {
//            e.printStackTrace();
//            throw new RuntimeException(e);//将检查异常转化为运行时异常
//        }
//    }
}
